using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PentaBiz.Collections.DataCache;

namespace PentaBiz.Testing.Collections.DataCache
{
    [TestClass]
    public class UnitTestSequentialDataCache100000Query
    {
        // private static SequentialDataCache<MyData> _sequentialDataCache;

        private const int PageSize = 10;

        [ClassInitialize]
        public static void Initialize(TestContext context)
        {
            if (File.Exists("profileCache100000.txt"))
                File.Delete("profileCache100000.txt");
        }



        [TestMethod]
        [TestCategory("SequentialDataCache")]
        public void TestIncrement5000TableValuesPerformance()
        {
            var _sequentialDataCache = SequentialDataCache<MyData>.Initialize(PageSize, deleteOnClose: true);


            for (int i = 0; i < 5000; i++)
            {
                var d = new MyData
                            {
                                Index = i,
                                Id = Guid.NewGuid(),
                                TwoDimensionDoubleArray = MyData.InitializeTwoDimensionDoubleArray(),
                                //TwoDimensionDecimalArray = MyData.InitializeTwoDimensionDecimalArray(),
                            };

                _sequentialDataCache.Add(d);
            }

            var rnd = new Random();
            //Assert.IsTrue(File.Exists(collection.Path));
            var sw = new Stopwatch();
            sw.Start();

            //increment random node values
            for (int i = 0; i < 5000; i++)
            {
                var index = rnd.Next(0, 5000);
                var d = _sequentialDataCache[i];

                //d.IncrementTableValuesUnsafe();
                d.IncrementTableValues();
            }

            //create result
            var result = _sequentialDataCache.ToSequentialDataCache();

            sw.Stop();
            Console.WriteLine("Ellapsed: {0}", sw.Elapsed);
            WriteResult(sw.Elapsed);

            result.Close();
            _sequentialDataCache.Close();

        }

        /// <summary>
        /// Tests the increment100000 table values performance.
        /// </summary>
        /// <remarks>
        /// 1. creates initial cache with 100.000 MyData
        /// 2. performs increment all double values in TwoDimensionDoubleArray
        /// 3. stores incremented values in new cache
        /// </remarks>
        [TestMethod]
        [TestCategory("SequentialDataCache")]
        public void TestIncrement100000TableValuesPerformance()
        {
            var _sequentialDataCache = SequentialDataCache<MyData>.Initialize(PageSize, deleteOnClose: true);


            for (int i = 0; i < 100000; i++)
            {
                var d = new MyData
                            {
                                Index = i,
                                Id = Guid.NewGuid(),
                                TwoDimensionDoubleArray = MyData.InitializeTwoDimensionDoubleArray(),
                                //TwoDimensionDecimalArray = MyData.InitializeTwoDimensionDecimalArray(),
                            };

                _sequentialDataCache.Add(d);
            }

            //condition
            Func<MyData, bool> itemCondition = c => true;

            //transformation
            Func<MyData, MyData> itemTransformation = data =>
                                                          {
                                                              data.IncrementTableValues();
                                                              return data;
                                                          };
           
            var sw = new Stopwatch();
            sw.Start();


           

            //create new transformation result for all items based on the condition
            var result = _sequentialDataCache.ToSequentialDataCache(itemCondition, itemTransformation, PageSize);

            sw.Stop();
            Console.WriteLine("Ellapsed: {0}", sw.Elapsed);
            WriteResult(sw.Elapsed);

            result.Close();
            _sequentialDataCache.Close();

        }


        private void WriteResult(TimeSpan ellapsed, [CallerMemberName] string caller = "")
        {
            File.AppendAllText("ProfileCache100000.txt", string.Format("* {0}: *{1}*\r\n", caller, ellapsed));
        }


        #region Nested type: MyData

        [Serializable]
        [DebuggerDisplay("MyData[{Index}]")]
        private class MyData
        {
            public int Index { get; set; }
            public Guid Id { get; set; }
            //public double[][] JaggedArray { get; set; }
            //public double[] OneDimensionArray { get; set; }
            public double[,] TwoDimensionDoubleArray { get; set; }
            //public decimal[,] TwoDimensionDecimalArray { get; set; }
            //public double[, ,] ThreeDimensionArray { get; set; }

            public void IncrementTableValues()
            {
                for (int i = 0; i < TwoDimensionDoubleArray.GetLength(0); i++)
                {
                    for (int j = 0; j < TwoDimensionDoubleArray.GetLength(1); j++)
                    {
                        TwoDimensionDoubleArray[i, j] += 1;
                    }
                }
            }

            public static double[] InitializeOneDimensionDoubleArray(int length1 = 3)
            {
                double v = 0;
                var d = new double[length1];
                for (int i = 0; i < length1; i++, v++)
                    d[i] = v;


                return d;
            }

            public static double[,] InitializeTwoDimensionDoubleArray(int length1 = 3, int length2 = 1000)
            {
                double v = 0;
                var d = new double[length1, length2];
                for (int i = 0; i < length1; i++)
                    for (int j = 0; j < length2; j++, v++)
                        d[i, j] = v;


                return d;
            }

            public static double[, ,] InitializeThreeDimensionDoubleArray(int length1 = 3, int length2 = 1000,
                                                                          int length3 = 2)
            {
                double v = 0;
                var d = new double[length1, length2, length3];
                for (int i = 0; i < length1; i++)
                    for (int j = 0; j < length2; j++)
                        for (int k = 0; k < length3; k++, v++)
                            d[i, j, k] = v;


                return d;
            }

            public static Decimal[] InitializeOneDimensionDecimalArray(int length1 = 3)
            {
                Decimal v = 0;
                var d = new Decimal[length1];
                for (int i = 0; i < length1; i++, v++)
                    d[i] = v;


                return d;
            }

            public static Decimal[,] InitializeTwoDimensionDecimalArray(int length1 = 3, int length2 = 1000)
            {
                Decimal v = 0;
                var d = new Decimal[length1, length2];
                for (int i = 0; i < length1; i++)
                    for (int j = 0; j < length2; j++, v++)
                        d[i, j] = v;


                return d;
            }

            public static Decimal[, ,] InitializeThreeDimensionDecimalArray(int length1 = 3, int length2 = 1000,
                                                                            int length3 = 2)
            {
                Decimal v = 0;
                var d = new Decimal[length1, length2, length3];
                for (int i = 0; i < length1; i++)
                    for (int j = 0; j < length2; j++)
                        for (int k = 0; k < length3; k++, v++)
                            d[i, j, k] = v;


                return d;
            }


            public static float[] InitializeOneDimensionFloatArray(int length1 = 3)
            {
                float v = 0;
                var d = new float[length1];
                for (int i = 0; i < length1; i++, v++)
                    d[i] = v;


                return d;
            }

            public static float[,] InitializeTwoDimensionFloatArray(int length1 = 3, int length2 = 1000)
            {
                float v = 0;
                var d = new float[length1, length2];
                for (int i = 0; i < length1; i++)
                    for (int j = 0; j < length2; j++, v++)
                        d[i, j] = v;


                return d;
            }

            public static float[, ,] InitializeThreeDimensionFloatArray(int length1 = 3, int length2 = 1000,
                                                                        int length3 = 2)
            {
                float v = 0;
                var d = new float[length1, length2, length3];
                for (int i = 0; i < length1; i++)
                    for (int j = 0; j < length2; j++)
                        for (int k = 0; k < length3; k++, v++)
                            d[i, j, k] = v;


                return d;
            }

            public static double[][] InitializeJaggedArray(int x = 3, int y = 1000)
            {
                var d = new double[x][];

                for (int i = 0; i < x; i++)
                {
                    d[i] = new double[y];
                    for (int j = 0; j < y; j++)
                        d[i][j] = i * j;
                }


                return d;
            }
        }

        #endregion
    }
}